home *** CD-ROM | disk | FTP | other *** search
- /* memory allocation routines
- * Copyright 1991 Phil Karn, KA9Q
- *
- * Adapted from alloc routine in K&R; memory statistics and interrupt
- * protection added for use with net package. Must be used in place of
- * standard Turbo-C library routines because the latter check for stack/heap
- * collisions. This causes erroneous failures because process stacks are
- * allocated off the heap.
- *
- * Mods by G1EMM , PA0GRI, KO4KS
- */
-
- #include <stdio.h>
- #include <dos.h>
- #include <alloc.h>
- #include "global.h"
- #include "config.h"
- #include "proc.h"
- #include "cmdparse.h"
- #include "mbuf.h"
-
- static unsigned long Memfail; /* Count of allocation failures */
- static unsigned long Allocs; /* Total allocations */
- unsigned long Frees; /* Total frees */
- static unsigned long Invalid; /* Total calls to free with garbage arg */
- static unsigned long Yellows; /* Yellow alert garbage collections */
- static unsigned long Reds; /* Red alert garbage collections */
- static unsigned long Overuse; /* Total calls to free with overused arg */
- static unsigned long Intalloc; /* Calls to malloc with ints disabled */
- static unsigned long Intfree; /* Calls to free with ints disabled */
- static int Memwait; /* Number of tasks waiting for memory */
- static unsigned long Availmem; /* Heap memory, ABLKSIZE units */
- static unsigned long ReallocSys;
- static unsigned long Morecores;
- #ifdef notdef
- static int Efficient = 1; /* 0 = normal/fast, 1 = effecient/slow */
- #endif
- static int Memdebug = 0; /* 0 = normal, 1 = call logstat() */
- #ifdef MULTITASK
- unsigned Minheap = 16 * 1024; /* Min free heap when shelling out */
- #endif
- static char freewarn[] ="free: WARNING! %s (%Fp) pc = %04x:%04x proc %s%c";
- static char freewarn1[] = "invalid pointer";
- static char HeapSizeStr[] = "heap size %lu, avail %lu (%lu%%), morecores %lu (-%lu), coreleft %lu";
- static char AllocStr[] = "allocs %lu, frees %lu (diff %lu), alloc fails %lu, invalid frees %lu, overused %lu";
- static char GarbageStr[] = "garbage collections yellow %lu, red %lu";
- #ifdef notdef
- static char EfficientStr[] = "efficient %u, threshold %lu";
- #else
- static char EfficientStr[] = "threshold %lu";
- #endif
- static char InterruptStr[] = "interrupts-off calls to malloc %lu, free %lu\n";
- #ifdef Kelvdebug
- static char freewarn2[] = "overused buffer";
- #endif
-
- extern void vmsstat();
- extern void displayStatLine __ARGS((int offset, int phase));
- extern char vgaDesired;
-
- static unsigned long Sizes[16];
-
- int logstat __ARGS((void));
-
- static int dostat __ARGS((int argc,char *argv[],void *p));
- static int dofreelist __ARGS((int argc,char *argv[],void *p));
- static int doibufsize __ARGS((int argc,char *argv[],void *p));
- static int donibufs __ARGS((int argc,char *argv[],void *p));
- static int dothresh __ARGS((int argc,char *argv[],void *p));
- static int dosizes __ARGS((int argc,char *argv[],void *p));
- static int doefficient __ARGS((int argc,char *argv[],void *p));
- static int domemdebug __ARGS((int argc,char *argv[],void *p));
- static int dominheap __ARGS((int argc,char *argv[],void *p));
- static int dogcollect __ARGS((int argc,char *argv[],void *p));
-
- struct cmds DFAR Memcmds[] = {
- "debug", domemdebug, 0, 0, NULLCHAR,
- #ifdef notdef
- "efficient", doefficient, 0, 0, NULLCHAR,
- #endif
- "freelist", dofreelist, 0, 0, NULLCHAR,
- "gcollect", dogcollect, 0, 0, NULLCHAR,
- "ibufsize", doibufsize, 0, 0, NULLCHAR,
- #ifdef MULTITASK
- "minheap", dominheap, 0, 0, NULLCHAR,
- #endif
- "nibufs", donibufs, 0, 0, NULLCHAR,
- "sizes", dosizes, 0, 0, NULLCHAR,
- "status", dostat, 0, 0, NULLCHAR,
- "thresh", dothresh, 0, 0, NULLCHAR,
- NULLCHAR,
- };
-
- #ifdef LARGEDATA
- #define HUGE huge
- #else
- #define HUGE
- #endif
-
- union header {
- struct {
- union header HUGE *ptr;
- unsigned long size;
- } s;
- long l[2];
- };
-
- typedef union header HEADER;
- #define NULLHDR (HEADER HUGE *)NULL
-
- #define ABLKSIZE (sizeof (HEADER))
-
- static HEADER HUGE *morecore __ARGS((unsigned nu));
-
- static HEADER Base;
- static HEADER HUGE *Allocp = NULLHDR;
- unsigned long Heapsize;
- static char HUGE *newbrk;
-
- #ifdef Kelvdebug
- #define MARKER 0x766c654bL /* Kelv in reverse */
- #endif
-
- /* Allocate block of 'nb' bytes */
- void *
- malloc(nb)
- unsigned nb;
- {
- register HEADER HUGE *p, HUGE *q;
- register unsigned nu;
- int i;
-
- if(!istate())
- Intalloc++;
- if(nb == 0)
- return NULL;
-
- /* Record the size of this request */
- if((i = log2(nb)) >= 0)
- Sizes[i]++;
-
- #ifndef Kelvdebug
- /* Round up to full block, then add one for header */
-
- nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 2; /* force allocated memory */
- nu &= 0xfffffffeL; /* to be on offset 0x0008 */
- #else
- /* Round up to full block, then add one for header and one for debug */
-
- nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 4; /* force allocated memory */
- nu &= 0xfffffffeL; /* to be on offset 0x0008 */
- #endif
-
- if ((q = Allocp) == NULLHDR){
- Base.s.ptr = Allocp = q = &Base;
- Base.s.size = 1;
- }
-
- #ifdef notdef
- if(Efficient) {
- Allocp = q = &Base; /* Start at the very beginning again */
- }
- #endif
-
- for (p = q->s.ptr; ; q = p, p = p->s.ptr){
- if (p->s.size >= nu){
- /* This chunk is at least as large as we need */
- if (p->s.size <= nu + 1){
- /* This is either a perfect fit (size == nu)
- * or the free chunk is just one unit larger.
- * In either case, alloc the whole thing,
- * because there's no point in keeping a free
- * block only large enough to hold the header.
- */
- q->s.ptr = p->s.ptr;
- } else {
- /* Carve out piece from end of entry */
- p->s.size -= nu;
- p += p->s.size;
- p->s.size = nu;
- }
- p->s.ptr = p; /* for auditing */
- #ifdef Kelvdebug
- p->l[(p->s.size * 2) - 2] = (long)p; /* debug */
- p->l[(p->s.size * 2) - 1] = MARKER; /* debug */
- #endif
- Allocs++;
- Availmem -= p->s.size;
- p++;
- #ifdef LARGEDATA
- /* On the brain-damaged Intel CPUs in
- * "large data" model, make sure the offset field
- * in the pointer we return isn't null.
- * The Turbo C compiler and certain
- * library functions like strrchr() assume this.
- */
- if(FP_OFF(p) == 0){
- /* Return denormalized but equivalent pointer */
- return (void *)MK_FP(FP_SEG(p)-1,16);
- }
- #endif
- return (void *)p;
- }
- if (p == Allocp && ((p = morecore(nu)) == NULLHDR)){
- Memfail++;
- return NULL;
- }
- }
- }
- /* Get more memory from the system and put it on the heap */
- static HEADER HUGE *
- morecore(nu)
- unsigned nu;
- {
- register HEADER HUGE *up;
-
- Morecores++;
- if ((int)(newbrk = (char HUGE *)sbrk(nu * ABLKSIZE)) == -1){
- if (Memdebug) {
- log(-1,"morecore: Failure requesting %ul (coreleft %ul)",
- (unsigned long) nu * ABLKSIZE,(unsigned long) coreleft());
- logstat();
- }
- return NULLHDR;
- }
-
- up = (HEADER *)newbrk;
- newbrk += (nu * ABLKSIZE);
- up->s.size = nu;
- up->s.ptr = up; /* satisfy audit */
- #ifdef Kelvdebug
- up->l[(up->s.size * 2) - 2] = (long)up; /* satisfy debug */
- up->l[(up->s.size * 2) - 1] = MARKER; /* satisfy debug */
- #endif
- free((void *)(up + 1));
- Heapsize += nu*ABLKSIZE;
- Frees--; /* Nullify increment inside free() */
- return Allocp;
- }
-
- extern void stktrace();
-
- /* Put memory block back on heap */
- void
- free(blk)
- void *blk;
- {
- register HEADER HUGE *p, HUGE *q;
- unsigned short HUGE *ptr;
-
- if(!istate())
- Intfree++;
- if(blk == NULL)
- return; /* Required by ANSI */
- p = (HEADER HUGE *)blk - 1;
- /* Audit check */
- if(p->s.ptr != p){
- ptr = (unsigned short *)&blk;
- printf(freewarn,freewarn1,blk,ptr[-1],ptr[-2],Curproc->name,'\n');
- fflush(stdout);
- #ifdef STKTRACE
- stktrace();
- #endif
- Invalid++;
- log(-1,freewarn,freewarn1,blk,ptr[-1],ptr[-2],Curproc->name,' ');
- logstat();
- return;
- }
- #ifdef Kelvdebug
- if(p->l[(p->s.size * 2) - 2] != (long)p || p->l[(p->s.size * 2) - 1] != MARKER){
- ptr = (unsigned short *)&blk;
- printf(freewarn,freewarn2,blk,ptr[-1],ptr[-2],Curproc->name,'\n');
- fflush(stdout);
- Overuse++;
- log(-1,freewarn,freewarn2,blk,ptr[-1],ptr[-2],Curproc->name,' ');
- logstat();
- return;
- }
- #endif
- Availmem += p->s.size;
- /* Search the free list looking for the right place to insert */
- for(q = Allocp; !(p > q && p < q->s.ptr); q = q->s.ptr){
- /* Highest address on circular list? */
- if(q >= q->s.ptr && (p > q || p < q->s.ptr))
- break;
- }
- if(p + p->s.size == q->s.ptr){
- /* Combine with front of this entry */
- p->s.size += q->s.ptr->s.size;
- p->s.ptr = q->s.ptr->s.ptr;
- } else {
- /* Link to front of this entry */
- p->s.ptr = q->s.ptr;
- }
- if(q + q->s.size == p){
- /* Combine with end of this entry */
- q->s.size += p->s.size;
- q->s.ptr = p->s.ptr;
- } else {
- /* Link to end of this entry */
- q->s.ptr = p;
- }
-
- Frees++;
- if(Memwait != 0)
- psignal(&Memwait,0);
- }
-
- #ifdef notdef /* Not presently used */
- /* Move existing block to new area */
- void *
- realloc(area,size)
- void *area;
- unsigned size;
- {
- unsigned osize;
- HEADER HUGE *hp;
- char HUGE *cp;
-
- hp = ((HEADER *)area) - 1;
- osize = (hp->s.size -1) * ABLKSIZE;
-
- free(area); /* Hopefully you have your interrupts off , Phil. */
- if((cp = malloc(size)) != NULL && cp != area)
- memcpy((char *)cp,(char *)area,size>osize? osize : size);
- return cp;
- }
- #endif
- /* Allocate block of cleared memory */
- void *
- calloc(nelem,size)
- unsigned nelem; /* Number of elements */
- unsigned size; /* Size of each element */
- {
- register unsigned i;
- register char *cp;
-
- i = nelem * size;
- if((cp = malloc(i)) != NULL)
- memset(cp,0,i);
- return cp;
- }
- /* Version of malloc() that waits if necessary for memory to become available */
- void *
- mallocw(nb)
- unsigned nb;
- {
- register void *p;
-
- while((p = malloc(nb)) == NULL){
- Memwait++;
- pwait(&Memwait);
- Memwait--;
- }
- return p;
- }
- /* Version of calloc that waits if necessary for memory to become available */
- void *
- callocw(nelem,size)
- unsigned nelem; /* Number of elements */
- unsigned size; /* Size of each element */
- {
- register unsigned i;
- register char *cp;
-
- i = nelem * size;
- cp = mallocw(i);
- memset(cp,0,i);
- return cp;
- }
- /* Return available memory on our heap plus available system memory */
- unsigned long
- availmem()
- {
- return Availmem * ABLKSIZE + coreleft();
- }
-
- /* Log heap stats */
- int
- logstat()
- {
- if(Memdebug){
- log(-1,"Memory status :");
- log(-1,HeapSizeStr,Heapsize,Availmem*ABLKSIZE, \
- 100L*Availmem*ABLKSIZE/Heapsize,Morecores,ReallocSys,coreleft());
- log(-1,AllocStr,Allocs,Frees,Allocs-Frees,Memfail,Invalid,Overuse);
- log(-1,GarbageStr,Yellows,Reds);
- #ifdef notdef
- log(-1,EfficientStr,Efficient,Memthresh);
- #else
- log(-1,EfficientStr,Memthresh);
- #endif
- log(-1,InterruptStr,Intalloc,Intfree);
- }
-
- return 0;
- }
-
- void
- mbmemory ()
- {
- tprintf(HeapSizeStr,Heapsize,Availmem*ABLKSIZE, \
- 100L*Availmem*ABLKSIZE/Heapsize,Morecores,ReallocSys,coreleft());
- tputc('\n');
- }
-
-
- /* Print heap stats */
- static int
- dostat(argc,argv,envp)
- int argc;
- char *argv[];
- void *envp;
- {
- mbmemory();
- tprintf(AllocStr,Allocs,Frees,Allocs-Frees,Memfail,Invalid,Overuse);
- tputc('\n');
- tprintf(GarbageStr,Yellows,Reds);
- tputc('\n');
- tprintf(InterruptStr,Intalloc,Intfree);
- vmsstat();
- iqstat();
- return 0;
- }
-
- /* Print heap free list */
- static int
- dofreelist(argc,argv,envp)
- int argc;
- char *argv[];
- void *envp;
- {
- HEADER HUGE *p;
- int i = 0;
-
- for(p = Base.s.ptr;p != &Base;p = p->s.ptr){
- tprintf("%4.4x %6lu",FP_SEG(p),p->s.size * ABLKSIZE);
- if(++i == 5){
- i = 0;
- if(tprintf("\n") == EOF)
- return 0;
- } else
- tprintf(" | ");
- }
- if(i != 0)
- tprintf("\n");
- return 0;
- }
- static int
- dosizes(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- int i;
-
- for(i=0;i<16;i += 4){
- tprintf("N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld\n",
- 1<<i,Sizes[i], 2<<i,Sizes[i+1],
- 4<<i,Sizes[i+2],8<<i,Sizes[i+3]);
- }
- return 0;
- }
- int
- domem(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return subcmd(Memcmds,argc,argv,p);
- }
-
- static int
- dothresh(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setlong(&Memthresh,"Free memory threshold (bytes)",argc,argv);
- }
-
- static int
- donibufs(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- if(setint(&Nibufs,"Interrupt pool buffers",argc,argv) == 0){
- iqclear();
- return 0;
- }
- return 1;
- }
- static int
- doibufsize(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setuns(&Ibufsize,"Interrupt buffer size",argc,argv);
- }
-
- static int
- dogcollect(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- void (**fp)();
-
- Yellows++;
- for(fp = Gcollect;*fp != NULL;fp++)
- (**fp)(0);
- tputs ("Garbage collection forced at Yellow level!\n");
- return 0;
- }
-
-
- void
- gcollect(i,v1,v2)
- int i; /* Args not used */
- char *v1;
- void *v2;
- {
- void (**fp)();
- int red;
- HEADER HUGE *p, *last;
- char HUGE *calc;
- unsigned long backto, backcnt;
- int backed;
-
- for(;;){
- mspause(500L); /* Run displayStatLine every 1/2 second */
- displayStatLine (0, 1);
- mspause(500L); /* and run the rest every second */
- displayStatLine (0, 0);
- #ifdef SCREENSAVER
- screensaver ();
- #endif
- /* If memory is low, collect some garbage. If memory is VERY
- * low, invoke the garbage collection routines in "red" mode.
- */
- if(availmem() < Memthresh){
- if(availmem() < Memthresh/2){
- red = 1;
- Reds++;
- } else {
- red = 0;
- Yellows++;
- }
- for(fp = Gcollect;*fp != NULL;fp++)
- (**fp)(red);
- }
- last = 0;
- for (p = Base.s.ptr; p->s.ptr != &Base; p = p->s.ptr)
- last = p;
- if (!last)
- continue;
- calc = (char HUGE *)(p + p->s.size);
- if (newbrk <= calc) {
- backcnt = backto = (p->s.size * ABLKSIZE);
- do {
- backed = (backcnt < 32767) ? backcnt : 32767;
- sbrk (-1 * backed);
- backcnt -= backed;
- } while (backcnt);
- newbrk -= backto;
- Heapsize -= backto;
- Availmem -= p->s.size;
- last->s.ptr = &Base;
- ReallocSys++;
- }
- }
- }
-
- #ifdef notdef
- static int
- doefficient(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setbool(&Efficient,"Efficient/slower mode",argc,argv);
- }
- #endif
-
- static int
- domemdebug(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setbool(&Memdebug,"\"Mem stat\" to log after failures",argc,argv);
- }
-
- #ifdef MULTITASK
- static int
- dominheap(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setuns(&Minheap,"Minimum free heap when shelled out",argc,argv);
- }
- #endif
-